package com.mine.yyb.common.utils.jdbc;

import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.support.TransactionTemplate;

import com.mine.yyb.common.utils.exception.MineErrorCode;

/**
 * <pre>
 * <一句话功能简述> 
 * jdbc 工具类 
 * <功能详细描述>
 * </pre>
 * 
 * @author xiongwei
 * @version [版本号, 2014年5月9日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Repository
public abstract class MineBaseDao extends NamedParameterJdbcDaoSupport
{
    
    // 日志
    private static final Logger logger = LoggerFactory.getLogger(MineBaseDao.class);
    
    @Resource
    private JdbcTemplate jdbcTemplate;
    
    /**
     * 事务控制模板
     */
    @Resource(name = "transactionTemplate")
    private TransactionTemplate transactionTemplate;
    
    /**
     * 注入dataSource
     * 
     * @param dataSource
     */
    @Resource(name = "dataSource")
    public void setSuperDataSource(DataSource dataSource)
    {
        setDataSource(dataSource);
    }
    
    /**
     * 普通DML操作,如insert,update,delete
     * 
     * @param sql
     * @return
     */
    public int update(String sql)
    {
        return this.jdbcTemplate.update(sql);
    }
    
    // /**
    // * 普通DML操作,如insert,update,delete
    // *
    // * @param sql
    // * @param params
    // * @return int 返回执行结果
    // */
    // public int update(String sql, Object[] params)
    // {
    // return this.jdbcTemplate.update(sql, params);
    // }
    
    /**
     * <pre>
     * <一句话功能简述>
     * 普通DML操作,如insert,update,delete
     * <功能详细描述>
     * </pre>
     * 
     * @author 王磊
     * @version [版本号, 2014年12月18日]
     * @param sql sql语句
     * @param paramsMap 存放参数的map集合
     * @return int 操作数据库返回结果 大于0：插入成功 0：插入失败
     * @see [类、类#方法、类#成员]
     */
    public int update(String sql, Map<String, Object> paramsMap)
    {
        return this.getNamedParameterJdbcTemplate().update(sql, paramsMap);
    }
    
    /**
     * 基于对象操作,如insert,update,delete
     * 
     * @param sql 执行的sql
     * @param omsTBase 参数类
     * @return int 返回执行结果
     */
    public int update(String sql, MineBaseVO omsTBase)
    {
        SqlParameterSource ps = new BeanPropertySqlParameterSource(omsTBase);
        
        return getNamedParameterJdbcTemplate().update(sql, ps);
    }
    
    /**
     * 批量普通DML操作,如insert,update,delete 由于需要预编译多条sql语句,效率低于batchUpdate(final String sql, final List<List<Object>>
     * paramsList)、batchUpdate(String sql, BatchPreparedStatementSetter pss)
     * 
     * @param sql
     * @return
     */
    public int[] batchUpdate(String[] sql)
    {
        
        return this.jdbcTemplate.batchUpdate(sql);
    }
    
    /**
     * 批量普通DML操作,如insert,update,delete 由于仅预编译1条sql语句执行效率较高
     * 
     * @param sql -
     * @param pss
     * @return
     */
    public int[] batchUpdate(String sql, BatchPreparedStatementSetter pss)
    {
        return this.jdbcTemplate.batchUpdate(sql, pss);
    }
    
    /**
     * 单行结果查询 (注：返回的结果行数大于1时将会抛出异常)
     * 
     * @param sql
     * @return
     */
    public Map<String, Object> queryForMap(String sql)
    {
        return this.jdbcTemplate.queryForMap(sql);
    }
    
    /**
     * <pre>
     * <一句话功能简述>
     * 单行结果查询 (注：返回的结果行数大于1时将会抛出异常)
     * <功能详细描述>
     * </pre>
     * 
     * @author wangl
     * @version [版本号, 2015年5月29日]
     * @param sql sql语句
     * @param omsTBase 参数
     * @return Map<String, Object> 查询结果
     * @see [类、类#方法、类#成员]
     */
    public Map<String, Object> queryForMap(String sql, MineBaseVO omsTBase)
    {
        SqlParameterSource ps = new BeanPropertySqlParameterSource(omsTBase);
        return this.getNamedParameterJdbcTemplate().queryForMap(sql, ps);
    }
    
    /**
     * <pre>
     * <一句话功能简述>
     * 查询单行数据 (注：返回的结果行数大于1时将会抛出异常)
     * <功能详细描述>
     * </pre>
     * 
     * @author 王磊
     * @version [版本号, 2015年2月14日]
     * @param sql sql语句
     * @param params 查询参数
     * @param rowMapper 实体
     * @return <T> 返回对象
     * @see [类、类#方法、类#成员]
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    public <T> T queryForObject(String sql, Map<String, Object> paramsMap, Class<T> rowMapper)
    {
        try
        {
            // 如果查询不到结果，则返回null对象
            return (T)this.getNamedParameterJdbcTemplate().queryForObject(sql,
                paramsMap,
                new BeanPropertyRowMapper(rowMapper));
        }
        catch (Exception e)
        {
            logger.error(MineErrorCode.ERROR_DB_EXECUTE_FAIL.name(), e);
            
            return null;
        }
        
    }
    
    /**
     * 
     * <pre>
     * <一句话功能简述>
     * 根据OmsBaseVO查询实体
     * <功能详细描述>
     * </pre>
     * 
     * @param sql 执行sql
     * @param omsTBase 参数
     * @param rowMapper 转换对象
     * @return <T> T
     * @see [类、类#方法、类#成员]
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public <T> T queryForObject(String sql, MineBaseVO omsTBase, Class<T> rowMapper)
    {
        try
        {
            SqlParameterSource ps = new BeanPropertySqlParameterSource(omsTBase);
            return (T)this.getNamedParameterJdbcTemplate().queryForObject(sql,
                ps,
                new BeanPropertyRowMapper(rowMapper));
        }
        catch (Exception e)
        {
            logger.error(MineErrorCode.ERROR_DB_EXECUTE_FAIL.name(), e);
            
            return null;
        }
        
    }
    
    /**
     * <pre>
     * <一句话功能简述>
     * 查询多行数据（有参数）
     * <功能详细描述>
     * 通过Map传递参数
     * </pre>
     * 
     * @author 王磊
     * @version [版本号, 2015年2月3日]
     * @param sql sql语句
     * @param paramsMap 参数
     * @param rowMapper 实例
     * @return List<T>
     * @see [类、类#方法、类#成员]
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public <T> List<T> queryForList(String sql, Map<String, Object> paramsMap, Class<T> rowMapper)
    {
        return this.getNamedParameterJdbcTemplate().query(sql, paramsMap, new BeanPropertyRowMapper(rowMapper));
    }
    
    /**
     * count,sum,max等查询
     * 
     * @param sql
     * @return
     */
    public int queryForInt(String sql)
    {
        return this.jdbcTemplate.queryForInt(sql);
    }
    
    /**
     * <pre>
     * <一句话功能简述>
     * count,sum,max等查询
     * <功能详细描述>
     * 通过map传递参数
     * </pre>
     * 
     * @author 王磊
     * @version [版本号, 2015年1月30日]
     * @param sql sql语句
     * @param paramsMap 需要的条件参数
     * @return long 返回值
     * @see [类、类#方法、类#成员]
     */
    public int queryForInt(String sql, Map<String, Object> paramsMap)
    {
        return this.getNamedParameterJdbcTemplate().queryForInt(sql, paramsMap);
    }
    
    /**
     * <pre>
     * <一句话功能简述>
     * 基于OmsTBase查询数据，count,sum,max等查询
     * <功能详细描述>
     * 通过OmsTBase传递参数
     * </pre>
     * 
     * @author 王磊
     * @version [版本号, 2015年1月30日]
     * @param sql sql语句
     * @param paramsMap 需要的条件参数
     * @return long 返回值
     * @see [类、类#方法、类#成员]
     */
    public int queryForInt(String sql, MineBaseVO omsTBase)
    {
        SqlParameterSource ps = new BeanPropertySqlParameterSource(omsTBase);
        return this.getNamedParameterJdbcTemplate().queryForInt(sql, ps);
        
    }
    
    /**
     * count,sum,max等查询
     * 
     * @param sql
     * @return
     */
    public long queryForLong(String sql)
    {
        return this.jdbcTemplate.queryForLong(sql);
    }
    
    /**
     * <pre>
     * <一句话功能简述>
     * count,sum,max等查询
     * <功能详细描述>
     * </pre>
     * 
     * @author 王磊
     * @version [版本号, 2015年9月17日]
     * @param sql sql语句
     * @param omsTBase 查询参数
     * @return List<Map<String, Object>> 返回多行数据
     * @see [类、类#方法、类#成员]
     */
    public long queryForLong(String sql, MineBaseVO omsTBase)
    {
        SqlParameterSource ps = new BeanPropertySqlParameterSource(omsTBase);
        return this.getNamedParameterJdbcTemplate().queryForLong(sql, ps);
    }
    
    /**
     * Map类型列表查询
     * 
     * @param sql
     * @return
     */
    public List<Map<String, Object>> queryForList(String sql)
    {
        return this.jdbcTemplate.queryForList(sql);
    }
    
    /**
     * <pre>
     * <一句话功能简述>
     * 查询多行数据
     * <功能详细描述>
     * </pre>
     * 
     * @author 王磊
     * @version [版本号, 2015年1月30日]
     * @param sql sql语句
     * @param omsTBase 查询参数
     * @return List<Map<String, Object>> 返回多行数据
     * @see [类、类#方法、类#成员]
     */
    public List<Map<String, Object>> queryForList(String sql, MineBaseVO omsTBase)
    {
        SqlParameterSource ps = new BeanPropertySqlParameterSource(omsTBase);
        return this.getNamedParameterJdbcTemplate().queryForList(sql, ps);
    }
    
    /**
     * <pre>
     * <一句话功能简述>
     * 查询多行数据
     * <功能详细描述>
     * </pre>
     * 
     * @author 王磊
     * @version [版本号, 2015年1月30日]
     * @param sql sql语句
     * @param paramsMap 查询参数
     * @return List<Map<String, Object>> 返回多行数据
     * @see [类、类#方法、类#成员]
     */
    public List<Map<String, Object>> queryForList(String sql, Map<String, Object> paramsMap)
    {
        return this.getNamedParameterJdbcTemplate().queryForList(sql, paramsMap);
    }
    
    /**
     * <pre>
     * <一句话功能简述>
     * 根据OmsTBase 查询数据
     * <功能详细描述>
     * </pre>
     * 
     * @author 王磊
     * @version [版本号, 2015年1月30日]
     * @param sql sql语句
     * @param omsTBase 查询参数
     * @return List<OmsTBase> 返回多行数据
     * @see [类、类#方法、类#成员]
     */
    public <T> List<T> queryForList(String sql, MineBaseVO omsTBase, Class<T> requiredType)
    {
        SqlParameterSource ps = new BeanPropertySqlParameterSource(omsTBase);
        return this.getNamedParameterJdbcTemplate().query(sql, ps, new BeanPropertyRowMapper<T>(requiredType));
    }
    
    /**
     * 执行DDL语句(alter,create,drop ...)
     * 
     * @param sql
     */
    public void execute(String sql)
    {
        this.jdbcTemplate.execute(sql);
    }
    
    /**
     * 获取总记录数sql语句
     * 
     * @param sql
     * @return String
     */
    public String getCountSql(String sql)
    {
        return String.format("select count(1) from (%s) as tmpTable", sql);
    }
    
    /**
     * 
     * <pre>
     * <一句话功能简述>
     * 根据map参数查询数据
     * <功能详细描述>
     * </pre>
     * 
     * @param sql 执行sql
     * @param params 参数条件
     * @param currentPage 当前页数
     * @param pageSize 每页显示数
     * @return OmsPagination<Map<String, Object>> 返回数据对象为map的OmsPagination
     * @see [类、类#方法、类#成员]
     */
    // public MinePagination<Map<String, Object>> queryForList(String sql, Map<String, Object> params, int currentPage,
    // int pageSize)
    // {
    // // 判断当前页是否合法
    // if (currentPage <= 0)
    // {
    // throw new IllegalArgumentException("currentPage is illegal");
    // }
    //
    // // 判断每页显示数是否合法
    // if (pageSize <= 0)
    // {
    // throw new IllegalArgumentException("pageSize is illegal");
    // }
    //
    // // 查询总记录数
    // int count = queryForInt(getCountSql(sql), params);
    //
    // MinePagination<Map<String, Object>> omsPagination =
    // new MinePagination<Map<String, Object>>(currentPage, pageSize, count);
    //
    // // 判断当前页是否小于总页数，如果大于总页数，则表示非法
    // if (currentPage > omsPagination.getTotalPage())
    // {
    // throw new IllegalArgumentException("currentPage is illegal,[currentPage:" + currentPage + ",totalPage:"
    // + omsPagination.getTotalPage() + "]");
    // }
    //
    // // 查询数据
    // List<Map<String, Object>> dataList = this.queryForList(getLimitSql(sql, currentPage, pageSize), params);
    // omsPagination.setDataList(dataList);
    //
    // return omsPagination;
    // }
    
    /**
     * 
     * <pre>
     * <一句话功能简述>
     * 根据对象查询数据数据
     * <功能详细描述>
     * </pre>
     * 
     * @param sql 执行sql
     * @param omsTBase 查询参数
     * @param requiredType 转换对象实体
     * @param currentPage 当前页数
     * @param pageSize 每页显示条数
     * @return <T> OmsPagination<T> 返回实体对象数据的OmsPagination
     * @see [类、类#方法、类#成员]
     */
    public <T> MinePagination<T> queryForList(String sql, MineBaseVO omsTBase, Class<T> requiredType, int sEcho,
        int iDisplayStart, int iDisplayLength)
    {
        if (sEcho < 0)
        {
            throw new IllegalArgumentException("sEcho is illegal");
        }
        
        if (iDisplayStart < 0)
        {
            throw new IllegalArgumentException("iDisplayStart is illegal");
        }
        
        if (iDisplayLength <= 0)
        {
            throw new IllegalArgumentException("iDisplayLength is illegal");
        }
        
        // 查询总记录数
        int count = queryForInt(getCountSql(sql), omsTBase);
        
        MinePagination<T> omsPagination = new MinePagination<T>(sEcho, count, count);
        
        // 判断当前页是否小于总页数，如果大于总页数，则表示非法
        if (iDisplayStart > count)
        {
            throw new IllegalArgumentException(
                "iDisplayStart is illegal,[iDisplayStart:" + iDisplayStart + ", iTotalRecords:" + count + "]");
        }
        
        // 查询数据
        List<T> dataList = queryForList(getLimitSql(sql, iDisplayStart, iDisplayLength), omsTBase, requiredType);
        omsPagination.setAaData(dataList);
        
        return omsPagination;
    }
    
    public <T> MinePagination<T> queryForList(String sql, Map<String, Object> paramsMap, int sEcho,
        int iDisplayStart, int iDisplayLength)
    {
        if (sEcho < 0)
        {
            throw new IllegalArgumentException("sEcho is illegal");
        }
        
        if (iDisplayStart < 0)
        {
            throw new IllegalArgumentException("iDisplayStart is illegal");
        }
        
        if (iDisplayLength <= 0)
        {
            throw new IllegalArgumentException("iDisplayLength is illegal");
        }
        
        // 查询总记录数
        int count = queryForInt(getCountSql(sql), paramsMap);
        
        MinePagination<T> omsPagination = new MinePagination<T>(sEcho, count, count);
        
        // 判断当前页是否小于总页数，如果大于总页数，则表示非法
        if (iDisplayStart > count)
        {
            throw new IllegalArgumentException(
                "iDisplayStart is illegal,[iDisplayStart:" + iDisplayStart + ", iTotalRecords:" + count + "]");
        }
        
        // 查询数据
        List dataList = queryForList(getLimitSql(sql, iDisplayStart, iDisplayLength), paramsMap);
        omsPagination.setAaData(dataList);
        
        return omsPagination;
    }
    
    /**
     * 获取分页sql语句
     * 
     * @param sql 主sql
     * @param currentPage 当前页数
     * @param pageSize 每页显示的总数
     * @return String 返回拼装的sql
     */
    public String getLimitSql(String sql, int iDisplayStart, int iDisplayLength)
    {
        return sql + "  LIMIT " + iDisplayStart + "," + iDisplayLength + " ";
    }
    
    /**
     * 
     * <pre>
     * <一句话功能简述>
     * 通过执行新增数据的sql获取该条数据的主键值
     * <功能详细描述>
     * 该方法只针对新增数据，该数据库必须设置自增长值的主键字段
     * </pre>
     * 
     * @param sql 执行的sql
     * @param vo 参数实体
     * @return int 返回该条数据的key值
     * @see [类、类#方法、类#成员]
     */
    public int getGeneratedKey(String sql, MineBaseVO vo)
    {
        
        SqlParameterSource ps = new BeanPropertySqlParameterSource(vo);
        
        KeyHolder keyHolder = new GeneratedKeyHolder();
        this.getNamedParameterJdbcTemplate().update(sql.toString(), ps, keyHolder);
        
        return keyHolder.getKey().intValue();
        
    }
    
}
